package com.ruihui.activity.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.ruihui.activity.exceprion.GetException;
import com.ruihui.activity.pojo.Acgoods;
import com.ruihui.activity.pojo.Acgrecord;
import com.ruihui.activity.service.AcgoodsService;
import com.ruihui.activity.service.AcgrecordService;
import com.ruihui.activity.util.AcgoodsType;
import com.ruihui.activity.util.ConstantHolder;
import com.ruihui.activity.util.DateUtil;
import com.ruihui.activity.util.Result;
import com.ruihui.activity.util.ResultCode;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
/**
 * 一般活动
 * @author cf
 *
 */
@Api(tags = "活动前台")
@RestController
@RequestMapping("/webActive")
public class WebActiveController {
	private static final Logger log = LoggerFactory.getLogger(WebActiveController.class);
	@Autowired
	private AcgrecordService acgrecordService;
	@Autowired
	private AcgoodsService acgoodsService;
	@Autowired
	private StringRedisTemplate redisTemplate;
	@Autowired
	private Redisson redisson;
	/**
	 * 查询活动商品集合
	 * 
	 * @param initials
	 *            活动首字母
	 * @param gname
	 *            活动商品名称（分类用）
	 * @param state
	 *            活动状态 （启动，关闭）
	 * @param type
	 *            活动类型（电脑，移动，全部）
	 * @param isnow
	 *            是否商品活动期间内（是，否）
	 * @param pageNo
	 *            页码
	 * @param pageSize
	 *            长度
	 * @return
	 */
	@ApiOperation(value = "活动商品缓存查询", response = Acgoods.class)
	@ApiImplicitParams({
			// @ApiImplicitParam(name = "gname", value = "活动商品分类名", required =
			// false,paramType="query"),
			// @ApiImplicitParam(name = "state", value = "活动商品状态 （1启动，2关闭）",
			// required = true, paramType="query"),
			// @ApiImplicitParam(name = "type", value = "活动商品类型（3电脑，2移动，1全部）",
			// required = true,paramType="query"),
			@ApiImplicitParam(name = "id", value = "活动id", required = true, paramType = "query"),

	})
	@GetMapping("/acgoodsList")
	public Object acgoodsList(Long id) {
		Result result = new Result();
		Map map = new HashMap();
		List<Acgoods> list = null;
		try {

			if (StringUtils.isEmpty(id)) {
				result.setMsg("活动id不能为空");
				result.setCode(-1);
				return result;
			} else {
				map.put("acid", id);
			}

			String acgoodsList = (String) redisTemplate.opsForValue().get(String.format(ConstantHolder.ACGLIST, id));
			// 一般为第一次查询时redis不存在值的情况，查询数据库存到redis缓存中
			if (StringUtils.isEmpty(acgoodsList)) {
				list = acgoodsService.getACgoodsList(map).getList();
				// 有数据进行缓存
				if (!list.isEmpty() && list.size() > 0) {
					String key = String.format(ConstantHolder.ACGLIST, id);
					String value = JSON.toJSON(list).toString();
					try {
						redisTemplate.opsForValue().set(key, value);
					} catch (Exception e) {
						log.error("redis缓存活动商品失败，请手动更新缓存，或者联系技术人员");
						result.setCode(-1);
						result.setMsg("redis缓存活动商品失败");
						return result;
					}
				}
				result.setData(list);
				result.setResultCode(ResultCode.SUCCESS);
				return result;
			}
			list = JSONObject.parseArray(acgoodsList, Acgoods.class);
			result.setData(list);
			result.setResultCode(ResultCode.SUCCESS);
			return result;
		} catch (Exception e) {
			return GetException.getCatch(e,log);
		}
	}

	/**
	 * 验证是否是不可重复活动商品中的有效活动
	 * 
	 * @param acid
	 *            活动id
	 * @param id
	 *            活动商品表id
	 * @param state
	 *            活动商品状态
	 * @param type
	 *            活动商品类型
	 * @return
	 */
	@ApiOperation(value = "验证是否是不可重复活动商品中的有效活动")
	@ApiImplicitParams({ 
			@ApiImplicitParam(name = "goodsid", value = "商品id", required = true, paramType = "query"),
			@ApiImplicitParam(name = "sessionid", value = "用户sessionid", required = true, paramType = "query"),
			@ApiImplicitParam(name = "buyNum", value = "用户购买数量", required = true, paramType = "query"), })
	@PostMapping("/iniacgoods")
	public Object iniacgoods(String sessionid, Long goodsid, Integer buyNum) {

		Result result = new Result();
		long nowdate = DateUtil.getDateline();
		Long memberId =null;
		try {
			
			if(!StringUtils.isEmpty(sessionid)){
				String ob=(String)redisTemplate.opsForValue().get(sessionid);
				memberId = ob == null ? null : Long.valueOf(ob);
				if(memberId==null){
					return Result.failure(ResultCode.USER_NOT_LOGGED_IN);
				}
			}
			// 验证
			return valid(memberId, goodsid, buyNum, result, nowdate);

		} catch (Exception e) {
			return GetException.getCatch(e,log);
		}
	}

	/**
	 * 减库存
	 * 
	 * @param memberId
	 *            用户id
	 * @param acid
	 *            活动id
	 * @param id
	 *            活动商品id
	 * @param state
	 *            活动商品状态
	 * @param type
	 *            活动商品类型
	 * @param buyNum
	 *            购买数量
	 * @return
	 */
	@ApiOperation(value = "验证并减库存加购买记录")
	@ApiImplicitParams({ 
//			@ApiImplicitParam(name = "acid", value = "活动id", required = true, paramType = "query"),
			@ApiImplicitParam(name = "goodsid", value = "商品id", required = true, paramType = "query"),
			@ApiImplicitParam(name = "sessionid", value = "用户sessionid", required = true, paramType = "query"),
			@ApiImplicitParam(name = "buyNum", value = "用户购买数量", required = true, paramType = "query"), })
	@PostMapping("/reduceNum")
	public Object reduceNum(String sessionid, Long goodsid, Integer buyNum) {
		Result result = new Result();
		long nowdate = DateUtil.getDateline();
		Long memberId =null;
		boolean flag = false;
		try {
			String lockKey = String.format(ConstantHolder.LOCK, goodsid);
		
			if(!StringUtils.isEmpty(sessionid)){
				String ob=(String)redisTemplate.opsForValue().get(sessionid);
				memberId = ob == null ? null : Long.valueOf(ob);
				if(memberId==null){
					return Result.failure(ResultCode.USER_NOT_LOGGED_IN);
				}
			}
			RLock lock = redisson.getFairLock(lockKey);
			try {
				flag = lock.tryLock(5, 30, TimeUnit.SECONDS);
				if (flag) {
					// 验证
					result = valid(memberId,  goodsid, buyNum, result, nowdate);
					// 验证通过
					if (result.getCode().intValue() == 1) {
						Acgoods acgoods = (Acgoods) result.getData();
						// 减库存
						acgoodsService.acreduceNum(acgoods, buyNum, acgoods.getId(), nowdate, memberId);

						result.setCode(1);
						result.setMsg("减库存成功");
						return result;

					} else {
						return result;
					}
				}
				return Result.errorMsg("减库存失败");
			} finally {
				lock.unlock();
			}
		
		} catch (Exception e) {
			return GetException.getCatch(e,log);
		}
	}
	/**
	 * 恢复活动库存
	 * @param sessionid
	 * @param acid
	 * @param buyNum
	 * @return
	 */
	@ApiOperation(value = "恢复活动库存")
	@ApiImplicitParams({ @ApiImplicitParam(name = "acid", value = "活动商品表id", required = true, paramType = "query"),
			@ApiImplicitParam(name = "sessionid", value = "用户sessionid", required = true, paramType = "query"),
			@ApiImplicitParam(name = "buyNum", value = "用户购买数量", required = true, paramType = "query"), })
	@PostMapping("/backNum")
	public Object backNum(String sessionid, Long acid, Integer buyNum) {
		Result result = new Result();
		Map map = new HashMap();
		Long memberId =null;
		try {
			
			if(!StringUtils.isEmpty(sessionid)){
				String ob=(String)redisTemplate.opsForValue().get(sessionid);
				memberId = ob == null ? null : Long.valueOf(ob);
				if(memberId==null){
					return Result.failure(ResultCode.USER_NOT_LOGGED_IN);
				}
			}

			Acgoods ag = acgoodsService.acBackNum(memberId, acid, buyNum);
			if(ag!=null){
				/*
				 * 更新缓存
				 */
				// 活动id
				map.put("acid", ag.getAcid());
				List<Acgoods> acgoodsList = acgoodsService.getACgoodsList(map).getList();
				String key = String.format(ConstantHolder.ACGLIST, ag.getAcid());
				String value = JSON.toJSON(acgoodsList).toString();
				try {
					redisTemplate.opsForValue().set(key, value);
				} catch (Exception e) {
					log.error("redis缓存活动商品失败，请手动更新缓存，或者联系技术人员");
					result.setCode(-1);
					result.setMsg("redis缓存活动商品失败");
					return result;
				}
			}
			
			result.setResultCode(ResultCode.SUCCESS);
			return result;

		} catch (Exception e) {
			return GetException.getCatch(e,log);
		}

	}

	
	// 验证是否是不可重复活动商品中的有效活动
	private Result valid(Long memberId, Long goodsid, Integer buyNum, Result result, long nowdate) {
		if (StringUtils.isEmpty(memberId)) {
			result.setMsg("请先登录");
			result.setCode(-1);
			return result;
		}
//		if (StringUtils.isEmpty(acid)) {
//			result.setMsg("活动id不能为空");
//			result.setCode(-1);
//			return result;
//		}
		if (StringUtils.isEmpty(goodsid)) {
			result.setMsg("商品id不能为空");
			result.setCode(-1);
			return result;
		}

		if (StringUtils.isEmpty(buyNum)) {
			result.setMsg("购买数量不能为空");
			result.setCode(-1);
			return result;
		}
		// 不可重复出现商品的活动时间内的商品
		String types=AcgoodsType.NOTREPETITION;
		Acgoods acgoods = acgoodsService.iniacGoods(goodsid, nowdate,types);

		if (!StringUtils.isEmpty(acgoods)) {
			// 购买记录
			PageInfo<Acgrecord> records = acgrecordService.getRecords(memberId, acgoods.getId(), goodsid,
					acgoods.getStarttime(), acgoods.getEndtime());
			if (acgoods.getAcnum().intValue() < buyNum.intValue()) {
				result.setMsg("活动商品库存不足");
				result.setCode(-1);
				return result;
			} else if (acgoods.getLimitbuy().intValue() < buyNum.intValue()) {
				result.setMsg("活动商品超过限购数量");
				result.setCode(-1);
				return result;
			} else if (records.getTotal() > acgoods.getChanceNum().intValue()) {
				result.setMsg("活动商品超过参与次数");
				result.setCode(-1);
				return result;
			} else {
				result.setResultCode(ResultCode.SUCCESS);
				result.setData(acgoods);
				return result;
			}
		} else {
			result.setMsg("活动商品过期");
			result.setCode(-1);
			return result;
		}
	}

}
